%    Copyright (C) 1989, 1996, 2002 Aladdin Enterprises.  All rights reserved.
% 
% This software is provided AS-IS with no warranty, either express or
% implied.
% 
% This software is distributed under license and may not be copied,
% modified or distributed except as expressly authorized under the terms
% of the license contained in the file LICENSE in this distribution.
% 
% For more information about licensing, please refer to
% http://www.ghostscript.com/licensing/. For information on
% commercial licensing, go to http://www.artifex.com/licensing/ or
% contact Artifex Software, Inc., 101 Lucas Valley Road #110,
% San Rafael, CA  94903, U.S.A., +1(415)492-9861.

% $Id: gs_epsf.ps,v 1.15 2005/08/30 23:26:49 alexcher Exp $
% Allow the interpreter to encapsulate EPS files, to recognize MS-DOS 
% EPSF file headers, and skip to the PostScript section of the file.

% Encapsulate EPS files and optionally resize page or rescale image.
% To display an EPS file cropped to the bounding box:
%  gs -dEPSCrop file.eps
% To display an EPS file scaled to fit the page:
%  gs -dEPSFitPage file.eps
% To display a file without EPS encapsulation:
%  gs -dNOEPS file.ps

% When starting to process an EPS file, state is 0.
% After %%BoundingBox processed, state is 1 if OK or 2 if cropped.
% After %%HiResBoundingBox processed, state is 3 if OK or 4 if cropped.
% After %%EndComments processed, state is 5.
/EPSBoundingBoxState 5 def
/EPSBoundingBoxSetState {
  //systemdict /EPSBoundingBoxState 3 -1 roll .forceput
} .bind odef % .forceput must be bound and hidden

% Parse 4 numbers for a bounding box
/EPSBoundingBoxParse { % (llx lly urx ury) -- llx lly urx ury true OR false
    mark exch
    token {exch token {exch token {exch token {exch pop} if} if} if} if
    counttomark
    4 eq {
      5 -1 roll pop % remove mark
      true
    } {
      cleartomark false
    } ifelse
} bind def

% Rescale and translate to fit the BoundingBox on the page
/EPSBoundingBoxFitPage { % llx lly urx ury --
  EPSDEBUG { (gs_epsf.ps: Rescaling EPS to fit page\n) print flush } if
  clippath pathbbox newpath
  % translate to new origin at lower left of clippath
  3 index 3 index translate
  % calculate scale to fit smaller of width or height
  exch 4 -1 roll sub 3 1 roll exch sub 
  4 2 roll 5 index 5 index 4 2 roll
  exch 4 -1 roll sub 3 1 roll exch sub 
  4 2 roll
  exch 4 -1 roll div 3 1 roll exch div
  1 index 1 index lt {pop}{exch pop} ifelse
  dup scale
  % translate to EPS -llx,-lly
  exch neg exch neg translate
} bind def

% Crop the page to the BoundingBox
/EPSBoundingBoxCrop { % llx lly urx ury --
  EPSDEBUG { 
    (gs_epsf.ps: Setting pagesize from EPS bounding box\n) print flush 
  } if
  exch 3 index sub exch 2 index sub % stack: llx lly urx-llx ury-lly
  << /PageSize [ 5 -2 roll ] >> setpagedevice
  neg exch neg exch translate
} bind def


/EPSBoundingBoxProcess { % (llx lly urx ury) state --
  //systemdict /EPSBoundingBoxState get 1 index lt {
    exch EPSBoundingBoxParse 
    {
      //systemdict /EPSCrop known {
        EPSBoundingBoxCrop
      } {
        //systemdict /EPSFitPage known {
          EPSBoundingBoxFitPage
	} {
	  % Warn if some of the EPS file will be clipped
	  clippath pathbbox newpath
	  { % context for exit
	    5 -1 roll lt { 6 { pop } repeat true exit } if
	    4 -1 roll lt { 4 { pop } repeat true exit } if
	    3 -1 roll gt { 2 { pop } repeat true exit } if
	    exch gt { true exit } if
	    false exit
	  } loop
	  QUIET not and /EPSBoundingBoxState .systemvar 1 and 1 eq and {
	    (\n   **** Warning: Some of the BoundingBox for the EPS file will be clipped.) =
	    (                 Use -dEPSCrop or -dEPSFitPage to avoid clipping.\n) =
	    flush
            1 add
          } if
	} ifelse
      } ifelse
      EPSBoundingBoxSetState
    } {
      pop % state
    } ifelse
  } {
    pop pop
  } ifelse
} bind def

/ProcessEPSComment { % file comment --  file comment
  //systemdict /EPSBoundingBoxState get 3 lt {
    dup
    (%%EndComments) anchorsearch {
      pop pop
      % ignore any following bounding boxes
      5 EPSBoundingBoxSetState
    } {
      (%%BoundingBox:) anchorsearch {
	pop 
	EPSDEBUG { (gs_epsf.ps: found %%BoundingBox\n) print flush } if
	1 EPSBoundingBoxProcess
      } {
	(%%HiResBoundingBox:) anchorsearch {
	  pop 
	  EPSDEBUG { (gs_epsf.ps: found %%HiResBoundingBox\n) print flush } if
	3 EPSBoundingBoxProcess
	} { 
	  pop % Not interested in this DSC comment
	} ifelse
      } ifelse
    } ifelse
  } if
} bind def

% Install EPS handler for DSC comments, which we do later
/EPSBoundingBoxInit {
  systemdict /NOEPS known not {
    % Merge ProcessEPSComment with existing handler
    /ProcessEPSComment load /exec load
    currentuserparams /ProcessDSCComment get 
    dup null eq {pop {pop pop}} if /exec load
    4 array astore cvx readonly
    << /ProcessDSCComment 3 -1 roll >> setuserparams
  } if
} bind def

/.runNoEPS /run load def

/.runEPS { % file OR string --
  /runEPS_save save def
  /runEPS_dict_count countdictstack def
  /runEPS_op_count count 2 sub def
  /runEPS_page_count currentpagedevice /PageCount get def 
  0 EPSBoundingBoxSetState
  .runNoEPS
  currentpagedevice /PageCount get runEPS_page_count sub 0 eq 
  { /showpage load exec } if
  count runEPS_op_count sub {pop} repeat
  countdictstack runEPS_dict_count sub {end} repeat
  runEPS_save restore
} bind def

/run { % file OR string --
  dup type /filetype ne { (r) file } if
  dup (%!PS-Adobe-) .peekstring {
    (%!PS-Adobe-) eq {
      dup (%!PS-Adobe-X.X EPSF-X.X) .peekstring {
      (EPSF) search {
        pop pop pop
        EPSDEBUG {(runEPS: Found EPS\n) print flush} if
        systemdict /NOEPS known {
          cvx .runNoEPS
        } {
          cvx .runEPS
        } ifelse
      } {
        EPSDEBUG {(runEPS: Normal DSC\n) print flush} if
        pop
          cvx .runNoEPS

      } ifelse
      } {
        EPSDEBUG {(runEPS: Short DSC\n) print flush} if
      pop
        cvx .runNoEPS
      } ifelse
    } {
      EPSDEBUG {(runEPS: Not DSC\n) print flush} if
      cvx .runNoEPS
    } ifelse
  } {
    EPSDEBUG {(runEPS: Short non-DSC\n) print flush} if
    pop
    cvx .runNoEPS
  } ifelse
} bind odef


% Handle DOS EPS files.

/.runnoepsf /run load def
/.epsfheader <C5D0D3C6> def
/run
 { dup type /filetype ne { (r) file } if
		% Check for MS-DOS EPSF file (see Red Book p. 729).
 dup (    ) .peekstring 
  { .epsfheader eq { dup (    ) readstring exch pop } { false } ifelse }
  { pop false }
 ifelse
		% Stack: file true/false
    {		% This block is executed if the file is MS-DOS EPSF.
		% Build up the little-endian byte offset and length.
      2
	{ 1 0 4
	   { 2 index read not { pop exit } if % if EOF, let error happen
	     2 index mul add exch 256 mul exch
	   }
	  repeat exch pop exch
	}
      repeat
		% Stack: offset length file
		% Use flushfile to skip quickly to the start of the
		% PostScript section.
      dup 4 -1 roll 12 sub () /SubFileDecode filter flushfile
		% Now interpret the PostScript.
      exch () /SubFileDecode filter cvx run
    }
    { .runnoepsf
    }
   ifelse
 } odef

% rebind .runstdin to use redefined run
userdict begin
/.runstdin {
  { (%stdin) run } execute0
} bind def
end
